﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Linq;

namespace Gmantis.Controls.Chart
{
    public enum ChartType
    {
        Bar,
        BarStacked,
        BarStacked100pc,
        Column,
        ColumnStacked,
        ColumnStacked100pc,
        Line,
        LineSmoothed,
        LineStacked,
        LineStacked100pc,
        LineSymbols,
        LineSymbolsStacked,
        LineSymbolsStacked100pc,
        LineSymbolsSmoothed,
        Area,
        AreaStacked,
        AreaStacked100pc,
        AreaSmoothed,
        Pie,
        PieExploded,
        PieDoughnut,
        PieExplodedDoughnut,
        PieStacked,
        XYPlot,
        Bubble,
        Radar,
        RadarSymbols,
        RadarFilled,
        HighLowOpenClose,
        Candle,
        Gantt,
        Step,
        StepSymbols,
        StepArea,
        StepAreaStacked,
        PolarLines,
        PolarSymbols,
        PolarLinesSymbols,
        Polygon,
        PolygonFilled
    }

    public enum GradientMethod
    {
        Auto,
        None,
        Linear,
        Radial
    }

    public enum ChartTheme
    {
        None,
        Custom,
        DuskBlue,
        DuskGreen,
        MediaPlayer,
        Office2003Blue,
        Office2003Classic,
        Office2003Olive,
        Office2003Royale,
        Office2003Silver,
        Office2007Black,
        Office2007Blue,
        Office2007Silver,
        Vista
    }

    [ContentProperty("Children")]
    public class Chart : ContentControl, IDisposable
    {
        // Fields
        private ActionCollection _actions;
        private bool? _autoSeries = false;
        private ChartBindings _bindings;
        private System.Collections.ObjectModel.ObservableCollection<UIElement> _children;
        private UIElement _content;
        private ResourceDictionary _customTheme = new ResourceDictionary();
        private bool _dirtyChildren = true;
        private VisualEffect _eff;
        private GradientMethod _gradientMethod;
        private bool _inBuild;
        private List<INotifyPropertyChanged> _inps = new List<INotifyPropertyChanged>();
        private ChartLegend _legend;
        private LegendItems _litems;
        private LegendItemCollection _litemsRO;
        private bool _loaded;
        private Renderers _renderers;
        private StyleGenerator _stgen;
        private bool _templated;
        private static ThemeConverter _themeConverter = new ThemeConverter();
        private int _updateCount;
        private FrameworkElement _viewElement;
        public static readonly DependencyProperty AggregateProperty = DependencyProperty.Register("Aggregate", typeof(Aggregate), typeof(Chart), new PropertyMetadata(Aggregate.None, new PropertyChangedCallback(Chart.OnAggregateChanged)));
        public static readonly DependencyProperty ChartTypeProperty = Utils.RegisterProperty("ChartType", typeof(ChartType), typeof(Chart), new PropertyChangedCallback(Chart.OnChartTypeChanged), ChartType.Column);
        public static readonly DependencyProperty ClipToBoundsProperty = DependencyProperty.Register("ClipToBounds", typeof(bool), typeof(Chart), new PropertyMetadata(false, new PropertyChangedCallback(Chart.OnClipToBoundsChanged)));
        public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(Chart), new PropertyMetadata(new CornerRadius(), new PropertyChangedCallback(Chart.OnCornerRadiusChanged)));
        public static readonly DependencyProperty CustomPaletteProperty = DependencyProperty.Register("CustomPalette", typeof(IEnumerable), typeof(Chart), new PropertyMetadata(null, new PropertyChangedCallback(Chart.OnCustomPaletteChanged)));
        public static DependencyProperty CustomThemeProperty = DependencyProperty.Register("CustomTheme", typeof(ResourceDictionary), typeof(Chart), new PropertyMetadata(null, new PropertyChangedCallback(Chart.OnCustomThemeChanged)));
        private bool dataChanged = true;
        private static readonly DependencyProperty DataContextInternalProperty = DependencyProperty.Register("DataContextInternal", typeof(object), typeof(Chart), new PropertyMetadata(null, new PropertyChangedCallback(Chart.OnDataContextInternalChanged)));
        public static readonly DependencyProperty DataProperty = Utils.RegisterProperty("Data", typeof(ChartData), typeof(Chart), new PropertyChangedCallback(Chart.OnDataChanged));
        internal bool forceRebuild = true;
        private static readonly DependencyProperty ForegroundInternalProperty = DependencyProperty.Register("ForegroundInternal", typeof(Brush), typeof(Chart), new PropertyMetadata(null, new PropertyChangedCallback(Chart.OnForegroundInternalChanged)));
        public static readonly DependencyProperty LegendItemsProperty = DependencyProperty.Register("LegendItems", typeof(LegendItemCollection), typeof(Chart), new PropertyMetadata(null, new PropertyChangedCallback(Chart.OnLegendItemsChanged)));
        internal bool rebuilding;
        private Size sz = new Size();
        public static DependencyProperty ThemeProperty = DependencyProperty.Register("Theme", typeof(ChartTheme), typeof(Chart), new PropertyMetadata(ChartTheme.None, new PropertyChangedCallback(Chart.OnThemeChanged)));
        public static readonly DependencyProperty ViewProperty = Utils.RegisterProperty("View", typeof(ChartView), typeof(Chart), new PropertyChangedCallback(Chart.OnViewChanged));

        // Events
        public event EventHandler ActionEnter;

        public event EventHandler ActionLeave;

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public event EventHandler LegendChanged;

        [EditorBrowsable(EditorBrowsableState.Never)]
        public event PropertyChangedEventHandler PropertyChanged;

        // Methods
        public Chart()
        {            
            base.DefaultStyleKey = typeof(Chart);
            base.LayoutUpdated += new EventHandler(this.Chart_LayoutUpdated);
            base.MouseLeftButtonDown += new MouseButtonEventHandler(this.OnMouseDown);
            base.MouseLeftButtonUp += new MouseButtonEventHandler(this.OnMouseUp);
            base.MouseMove += new MouseEventHandler(this.OnMouseMove);
            BubbleOptions.SetMinSize(this, Size.Empty);
            BubbleOptions.SetMaxSize(this, Size.Empty);
            this.Data = new ChartData();
            this.View = new ChartView();
            base.SetBinding(DataContextInternalProperty, new Binding());
            Binding binding = new Binding
            {
                Source = this,
                Path = new PropertyPath("Foreground", new object[0])
            };
            base.SetBinding(ForegroundInternalProperty, binding);
            base.Loaded += new RoutedEventHandler(this.Chart_Loaded);
            this._litems = new LegendItems();
            this._litemsRO = new LegendItemCollection(this._litems);
            this.LegendItems = this._litemsRO;
        }

        private void _actions_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
        }

        private void _children_Clear(object sender, EventArgs e)
        {
            this.RemoveChildren(this.Children);
        }

        private void _children_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action != NotifyCollectionChangedAction.Reset)
            {
                this.RemoveChildren(e.OldItems);
            }
            this.UpdateChildren();
        }

        private void _data_DataChanged(object sender, EventArgs e)
        {
            System.Action a = null;
            if (!this.rebuilding)
            {
                if ((this.Data != null) && (this.Data.Children.Count == 0))
                {
                    this.StyleGenerator.Reset();
                }
                this.forceRebuild = true;
                this.dataChanged = true;
                if (a == null)
                {
                    a = delegate
                    {
                        if (this.dataChanged)
                        {
                            this.InvalidateChart();
                        }
                    };
                }
                base.Dispatcher.BeginInvoke(a);
            }
        }

        private void AddINP(INotifyPropertyChanged inp)
        {
            inp.PropertyChanged += new PropertyChangedEventHandler(this.inp_PropertyChanged);
            this._inps.Add(inp);
        }

        internal void AddLogicalChild(object child)
        {
        }

        internal void ApplyChartType(ChartType chartType)
        {
            this.ApplyChartType(chartType.ToString());
        }

        private void ApplyChartType(string type)
        {
            if (!string.IsNullOrEmpty(type))
            {
                ChartSubtype subtype = ChartTypes.GetSubtype(type);
                if (subtype != null)
                {
                    subtype.Apply(this);
                }
            }
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            if (this._content != null)
            {
                if (this.ClipToBounds)
                {
                    RectangleGeometry geometry = new RectangleGeometry
                    {
                        Rect = new Rect(0.0, 0.0, finalSize.Width, finalSize.Height)
                    };
                    this._content.Clip = geometry;
                }
                else
                {
                    this._content.Clip = null;
                }
            }
            Size size = base.ArrangeOverride(finalSize);
            if (!this.IsInVisualTree())
            {
                this.RebuildChart();
            }
            return size;
        }

        public void BeginUpdate()
        {
            this.UpdateCount++;
        }

        private Brush BrushConverter(Brush brush)
        {
            if (this.GradientMethod != GradientMethod.None)
            {
                if ((!this.ChartType.ToString().StartsWith("Pie") || (this.GradientMethod != GradientMethod.Auto)) && (this.GradientMethod != GradientMethod.Radial))
                {
                    return brush;
                }
                LinearGradientBrush brush2 = brush as LinearGradientBrush;
                if ((brush2 == null) || (brush2.GradientStops == null))
                {
                    return brush;
                }
                GradientStopCollection gradientStopCollection = new GradientStopCollection();
                for (int i = 0; i < brush2.GradientStops.Count; i++)
                {
                    GradientStop stop = new GradientStop
                    {
                        Color = brush2.GradientStops[i].Color,
                        Offset = brush2.GradientStops[i].Offset
                    };
                    gradientStopCollection.Add(stop);
                }
                RadialGradientBrush brush3 = new RadialGradientBrush(gradientStopCollection);
                brush = brush3;
            }
            return brush;
        }

        private void Chart_LayoutUpdated(object sender, EventArgs e)
        {
            this.LayoutUpdatedInternal();
        }

        private void Chart_Loaded(object sender, RoutedEventArgs e)
        {
            this._loaded = true;
            if (!this._templated)
            {
                base.ApplyTemplate();
            }
            this.RebuildChart();
            if (this.ViewElement != null)
            {
                this.ViewElement.Width = base.Width;
                this.ViewElement.Height = base.Height;
            }
        }

        private void ClearAllINP()
        {
            int count = this._inps.Count;
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    this._inps[i].PropertyChanged -= new PropertyChangedEventHandler(this.inp_PropertyChanged);
                }
                this._inps.Clear();
            }
        }

        internal void ClearLegendBindings()
        {
            if (this._legend != null)
            {
                ClearValue(this._legend, Control.BackgroundProperty);
                ClearValue(this._legend, Control.ForegroundProperty);
                ClearValue(this._legend, Control.BorderBrushProperty);
                ClearValue(this._legend, Control.BorderThicknessProperty);
                ClearValue(this._legend, ChartLegend.CornerRadiusProperty);
            }
        }

        private void ClearThemeBindings()
        {
            FrameworkElement templateChild = base.GetTemplateChild("view") as FrameworkElement;
            if (templateChild != null)
            {
                ClearValue(templateChild, Border.BackgroundProperty);
                ClearValue(templateChild, Border.BorderBrushProperty);
                ClearValue(templateChild, Border.BorderThicknessProperty);
                ClearValue(templateChild, Border.CornerRadiusProperty);
                ClearValue(templateChild, Border.PaddingProperty);
            }
            ClearValue(this.View, ChartView.PlotBackgroundProperty);
            ClearValue(this, Control.BackgroundProperty);
            ClearValue(this, Control.ForegroundProperty);
            ClearValue(this, Control.BorderThicknessProperty);
            ClearValue(this, Control.BorderBrushProperty);
            ClearValue(this, FrameworkElement.MarginProperty);
            ClearValue(this, Control.PaddingProperty);
            ClearValue(this, CornerRadiusProperty);
            ClearValue(this, CustomPaletteProperty);
            this.ClearLegendBindings();
        }

        private static void ClearValue(FrameworkElement fe, DependencyProperty dp)
        {
            if ((fe != null) && (fe.ReadLocalValue(dp) is BindingExpressionBase))
            {
                fe.ClearValue(dp);
            }
        }

        private void EffectChanged(object sender, EventArgs e)
        {
            this.InvalidateChart();
        }

        public void EndUpdate()
        {
            this.UpdateCount--;
        }

        public object FindPlotElement(string name)
        {
            return this.ViewElement.FindName(name);
        }

        internal void FireActionEnter(object sender, EventArgs args)
        {
            if (this.ActionEnter != null)
            {
                this.ActionEnter(sender, args);
            }
        }

        internal void FireActionLeave(object sender, EventArgs args)
        {
            if (this.ActionLeave != null)
            {
                this.ActionLeave(sender, args);
            }
        }

        private void inc_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            this._data_DataChanged(this, EventArgs.Empty);
        }

        internal void InitLegendBindings(ChartLegend legend)
        {
            this._legend = legend;
            if (legend != null)
            {
                this.InitThemeBinding(legend, Control.BackgroundProperty, "Chart_LegendBackground_Brush");
                this.InitThemeBinding(legend, Control.ForegroundProperty, "Chart_LegendForeground_Brush");
                this.InitThemeBinding(legend, Control.BorderBrushProperty, "Chart_LegendBorder_Brush");
                this.InitThemeBinding(legend, Control.BorderThicknessProperty, "Chart_LegendBorder_Thickness");
                this.InitThemeBinding(legend, ChartLegend.CornerRadiusProperty, "Chart_Legend_CornerRadius");
            }
        }

        private void InitThemeBinding(FrameworkElement fe, DependencyProperty property, string key)
        {
            if ((((this.CustomTheme != null) && (fe != null)) && ((this.CustomTheme == null) || this.CustomTheme.Contains(key))) && (fe.ReadLocalValue(property) == DependencyProperty.UnsetValue))
            {
                Binding binding = new Binding
                {
                    Source = this,
                    Path = new PropertyPath("CustomTheme", new object[0])
                };
                binding.Mode = BindingMode.OneWay;
                binding.Converter = _themeConverter;
                binding.ConverterParameter = new object[] { key, fe };
                fe.SetBinding(property, binding);
            }
        }

        private void InitThemeBindings()
        {
            FrameworkElement templateChild = base.GetTemplateChild("view") as FrameworkElement;
            if (templateChild != null)
            {
                this.InitThemeBinding(templateChild, Border.BackgroundProperty, "Chart_ChartAreaBackground_Brush");
                this.InitThemeBinding(templateChild, Border.BorderBrushProperty, "Chart_ChartAreaBorder_Brush");
                this.InitThemeBinding(templateChild, Border.BorderThicknessProperty, "Chart_ChartAreaBorder_Thickness");
                this.InitThemeBinding(templateChild, Border.CornerRadiusProperty, "Chart_ChartArea_CornerRadius");
                this.InitThemeBinding(templateChild, Border.PaddingProperty, "Chart_ChartArea_Padding");
            }
            this.InitThemeBinding(this.View, ChartView.PlotBackgroundProperty, "Chart_PlotAreaBackground_Brush");
            this.InitThemeBinding(this, Control.BackgroundProperty, "Chart_Background_Brush");
            this.InitThemeBinding(this, Control.ForegroundProperty, "Chart_Foreground_Brush");
            this.InitThemeBinding(this, Control.BorderThicknessProperty, "Chart_Border_Thickness");
            this.InitThemeBinding(this, Control.BorderBrushProperty, "Chart_Border_Brush");
            this.InitThemeBinding(this, FrameworkElement.MarginProperty, "Chart_Margin");
            this.InitThemeBinding(this, Control.PaddingProperty, "Chart_Padding");
            this.InitThemeBinding(this, CornerRadiusProperty, "Chart_CornerRadius");
            this.InitThemeBinding(this, CustomPaletteProperty, "Chart_CustomPalette");
            this.InitLegendBindings(this._legend);
        }

        private void inp_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this._data_DataChanged(this, EventArgs.Empty);
        }

        internal void InvalidateChart()
        {
            if ((this.UpdateCount <= 0) && (((this.UpdateCount <= 0) && this._loaded) && this._templated))
            {
                this.forceRebuild = true;
                this.RebuildChart();
            }
        }

        internal void LayoutUpdatedInternal()
        {
            System.Action a = null;
            System.Action action2 = null;
            if (((base.ActualWidth != 0.0) && (base.ActualHeight != 0.0)) && this._loaded)
            {
                if (!this._templated)
                {
                    base.ApplyTemplate();
                }
                if (this._dirtyChildren)
                {
                    this.UpdateChildren();
                }
                Size size = new Size(base.ActualWidth, base.ActualHeight);
                if (size != this.sz)
                {
                    this.sz = size;
                    this.forceRebuild = true;
                    if (a == null)
                    {
                        a = () => this.RebuildChart();
                    }
                    base.Dispatcher.BeginInvoke(a);                    
                }
                else if ((this.ViewElement != null) && (this.ViewElement.Parent is FrameworkElement))
                {
                    FrameworkElement templateChild = base.GetTemplateChild("viewContent") as FrameworkElement;
                    if ((templateChild != null) && ((templateChild.ActualHeight != this.ViewElement.Height) || (templateChild.ActualWidth != this.ViewElement.Width)))
                    {
                        this.Data.Renderer.Dirty = true;
                        this.forceRebuild = true;
                        if (action2 == null)
                        {
                            action2 = () => this.RebuildChart();
                        }
                        base.Dispatcher.BeginInvoke(action2);
                    }
                }
            }
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            if (this.View != null)
            {
                this.ViewElement = this.View.ViewElement;
            }
            return base.MeasureOverride(availableSize);
        }

        private static void OnAggregateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Chart chart = (Chart)obj;
            if (chart.Data != null)
            {
                foreach (DataSeries series in chart.Data.Children)
                {
                    series.Dirty = true;
                }
            }
            chart.dataChanged = true;
            chart.forceRebuild = true;
            chart.InvalidateChart();
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            if (this.CustomTheme != null)
            {
                this.InitThemeBindings();
            }
            this._templated = true;
            this._dirtyChildren = true;
            this._content = base.GetTemplateChild("content") as UIElement;
        }

        internal static void OnAttachedPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Chart chart = obj as Chart;
            if (chart != null)
            {
                if (args.NewValue != args.OldValue)
                {
                    chart.forceRebuild = true;
                    chart.InvalidateChart();
                }
            }
            else
            {
                DataSeries series = obj as DataSeries;
                if (series != null)
                {
                    series.FirePropertyChanged(args.Property.ToString());
                }
            }
        }

        private static void OnChartTypeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Chart chart = (Chart)obj;
            ChartType newValue = (ChartType)args.NewValue;
            if (chart._loaded && chart._templated)
            {
                chart.ApplyChartType(newValue);
            }
        }

        private static void OnClipToBoundsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ((Chart)obj).InvalidateArrange();
        }

        private static void OnCornerRadiusChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
        }

        private static void OnCustomPaletteChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Chart chart = (Chart)obj;
            chart.StyleGenerator.Reset();
            object newValue = args.NewValue;
            IList<Color> list = newValue as IList<Color>;
            if (list != null)
            {
                Brush[] brushArray = new Brush[list.Count];
                for (int i = 0; i < list.Count; i++)
                {
                    brushArray[i] = new SolidColorBrush(list[i]);
                }
                newValue = brushArray;
            }
            Brush[] brushArray2 = newValue as Brush[];
            if ((brushArray2 != null) && (brushArray2.Length > 0))
            {
                chart.StyleGenerator.CustomBrushes = brushArray2;
            }
            else if (brushArray2 != null)
            {
                IList<Brush> list2 = (IList<Brush>)brushArray2;
                int count = list2.Count;
                if (count > 0)
                {
                    Brush[] brushArray3 = new Brush[count];
                    for (int j = 0; j < count; j++)
                    {
                        brushArray3[j] = list2[j];
                    }
                    chart.StyleGenerator.CustomBrushes = brushArray3;
                }
            }
            else
            {
                ResourceDictionary dictionary = newValue as ResourceDictionary;
                if (dictionary == null)
                {
                    IEnumerable enumerable = newValue as IEnumerable;
                    if (enumerable != null)
                    {
                        IEnumerator enumerator = enumerable.GetEnumerator();
                        List<Brush> list4 = new List<Brush>();
                        while (enumerator.MoveNext())
                        {
                            object current = enumerator.Current;
                            if (current is Brush)
                            {
                                list4.Add((Brush)current);
                            }
                            else if (current is Color)
                            {
                                list4.Add(new SolidColorBrush((Color)current));
                            }
                        }
                        chart.StyleGenerator.CustomBrushes = (list4.Count > 0) ? list4.ToArray() : null;
                    }
                    else
                    {
                        chart.StyleGenerator.CustomBrushes = null;
                    }
                }
                else
                {
                    List<Brush> list3 = new List<Brush>();
                    int num4 = 0;
                    while (true)
                    {
                        string key = num4.ToString();
                        if (!dictionary.Contains(key))
                        {
                            break;
                        }
                        Brush item = dictionary[key] as Brush;
                        if (item != null)
                        {
                            list3.Add(item);
                        }
                        num4++;
                    }
                    chart.StyleGenerator.CustomBrushes = (list3.Count > 0) ? list3.ToArray() : null;
                }
            }
            chart.InvalidateChart();
        }

        private static void OnCustomThemeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Chart sender = (Chart)obj;
            sender.BeginUpdate();
            if (sender.PropertyChanged != null)
            {
                sender.PropertyChanged(sender, new PropertyChangedEventArgs("CustomTheme"));
            }
            if ((sender.Data != null) && (sender.Data.Renderer != null))
            {
                sender.Data.Renderer.Dirty = true;
            }
            sender.EndUpdate();
            ResourceDictionary newValue = args.NewValue as ResourceDictionary;
            if (!Themes.IsStandard(newValue))
            {
                sender.Theme = ChartTheme.Custom;
            }
        }

        private static void OnDataChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Chart chart = (Chart)obj;
            chart.ClearAllINP();
            ChartData oldValue = (ChartData)args.OldValue;
            if (oldValue != null)
            {
                if (((oldValue.Renderer == chart.Renderers.Pie) || (oldValue.Renderer == chart.Renderers.Radar)) || (oldValue.Renderer == chart.Renderers.Renderer2D))
                {
                    oldValue.Renderer = null;
                }
                oldValue.DataChanged -= new EventHandler(chart._data_DataChanged);
                chart.RemoveLogicalChild(oldValue);
            }
            oldValue = (ChartData)args.NewValue;
            if (oldValue != null)
            {
                oldValue.DataChanged += new EventHandler(chart._data_DataChanged);
            }
            chart.StyleGenerator.Reset();
            if (oldValue != null)
            {
                oldValue.Renderer = null;
                chart.AddLogicalChild(oldValue);
            }
            chart.InvalidateChart();
        }

        private static void OnDataContextInternalChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Chart sender = (Chart)obj;
            INotifyCollectionChanged oldValue = args.OldValue as INotifyCollectionChanged;
            if (oldValue != null)
            {
                oldValue.CollectionChanged -= new NotifyCollectionChangedEventHandler(sender.inc_CollectionChanged);
            }
            else
            {
                INotifyPropertyChanged changed2 = args.OldValue as INotifyPropertyChanged;
                if (changed2 != null)
                {
                    changed2.PropertyChanged -= new PropertyChangedEventHandler(sender.inp_PropertyChanged);
                }
            }
            oldValue = args.NewValue as INotifyCollectionChanged;
            if (oldValue != null)
            {
                oldValue.CollectionChanged += new NotifyCollectionChangedEventHandler(sender.inc_CollectionChanged);
            }
            else
            {
                INotifyPropertyChanged newValue = args.NewValue as INotifyPropertyChanged;
                if (newValue != null)
                {
                    newValue.PropertyChanged += new PropertyChangedEventHandler(sender.inp_PropertyChanged);
                }
            }
            sender._data_DataChanged(sender, EventArgs.Empty);
        }

        private static void OnForegroundInternalChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ((Chart)obj).InvalidateChart();
        }

        private static void OnLegendItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Chart chart = (Chart)obj;
            if (args.NewValue != chart._litemsRO)
            {
                chart.LegendItems = chart._litemsRO;
            }
        }

        private void OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (this.Actions.Count > 0)
            {
                this.Actions.OnMouseDown(e);
            }
        }

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (this.Actions.Count > 0)
            {
                this.Actions.OnMouseMove(e);
            }
        }

        private void OnMouseUp(object sender, MouseButtonEventArgs e)
        {
            if (this.Actions.Count > 0)
            {
                this.Actions.OnMouseUp(e);
            }
        }

        protected override void OnMouseWheel(System.Windows.Input.MouseWheelEventArgs e)
        {
            base.OnMouseWheel(e);
            if (this.Actions.Count > 0)
            {
                this.Actions.OnMouseWheel(e);
            }
        }

        private static void OnThemeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Chart chart = (Chart)obj;
            ChartTheme oldValue = (ChartTheme)args.OldValue;
            ChartTheme newValue = (ChartTheme)args.NewValue;
            if (newValue != ChartTheme.Custom)
            {
                chart.CustomTheme = Themes.GetThemes((ChartTheme)args.NewValue);
            }
            chart.ClearThemeBindings();
            if (newValue != ChartTheme.None)
            {
                chart.InitThemeBindings();
            }
            chart.InvalidateChart();
        }

        private static void OnViewChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Chart chart = (Chart)obj;
            ChartView oldValue = (ChartView)args.OldValue;
            if (oldValue != null)
            {
                chart.RemoveLogicalChild(oldValue);
                oldValue.Chart = null;
            }
            oldValue = (ChartView)args.NewValue;
            if (oldValue != null)
            {
                oldValue.Chart = chart;
            }
            chart.InvalidateChart();
        }

        private void RebuildChart()
        {
            if (!this._inBuild)
            {
                DateTime now = DateTime.Now;
                try
                {
                    BaseRenderer renderer;
                    this._inBuild = true;
                    if (this.Data != null)
                    {
                        IRenderer renderer2 = this.Data.Renderer;
                        if (renderer2 == null)
                        {
                            this.ApplyChartType(this.ChartType);
                            renderer2 = this.Data.Renderer;
                            if (renderer2 == null)
                            {
                                this.Data.Renderer = renderer2 = new Renderer2D();
                            }
                        }
                        renderer = renderer2 as BaseRenderer;
                        if (renderer != null)
                        {
                            renderer.StyleGen = this.StyleGenerator;
                        }
                        renderer2.Visual = this;
                        if (renderer2.Dirty)
                        {
                            this.forceRebuild = true;
                        }
                    }
                    if (this.forceRebuild)
                    {
                        this.forceRebuild = false;
                        if (this.Data != null)
                        {
                            IRenderer renderer3 = this.Data.Renderer;
                            if (renderer3 != null)
                            {
                                renderer = renderer3 as BaseRenderer;
                                if (renderer != null)
                                {
                                    renderer.ChartType = this.ChartType;
                                    renderer.StyleGen.Reset();
                                }
                                renderer3.Dirty = false;
                                this.View.Renderer = renderer3;
                                if (this.dataChanged)
                                {
                                    this.dataChanged = false;
                                    renderer3.Clear();
                                    this.RebuildRenderer(renderer3);
                                }
                                if (renderer != null)
                                {
                                    object[] itemNamesInternal = this.Data.ItemNamesInternal;
                                    if ((this.Data.Aggregate != Aggregate.None) && (itemNamesInternal != null))
                                    {
                                        renderer.ItemNames = itemNamesInternal.Distinct<object>().ToArray<object>();
                                    }
                                    else
                                    {
                                        renderer.ItemNames = itemNamesInternal;
                                    }
                                    renderer.UpdateLegend(this.LegendItemsInternal);
                                }
                            }
                        }
                        if (this.View != null)
                        {
                            this.ViewElement = this.View.ViewElement;
                            FrameworkElement templateChild = base.GetTemplateChild("viewContent") as FrameworkElement;
                            if (templateChild != null)
                            {
                                double actualWidth = templateChild.ActualWidth;
                                double actualHeight = templateChild.ActualHeight;
                                this.ViewElement.Width = actualWidth;
                                this.ViewElement.Height = actualHeight;                                
                                this.View.Rebuild(actualWidth, actualHeight);
                            }
                            if (this.LegendChanged != null)
                            {
                                this.LegendChanged(this, EventArgs.Empty);
                            }
                            this.ViewElement.InvalidateArrange();
                        }
                    }
                }
                finally
                {
                    this._inBuild = false;
                }
            }
        }

        private void RebuildRenderer(IRenderer renderer)
        {
            IEnumerable itemsSource = this.Data.ItemsSource;
            this.ClearAllINP();
            if (itemsSource == null)
            {
                itemsSource = base.DataContext as IEnumerable;
            }
            if (itemsSource != null)
            {
                DataBindingHelper.AutoCreateSeries(this, itemsSource);
                List<object> list = null;
                Binding itemNameBinding = this.Data.ItemNameBinding;
                if ((itemNameBinding == null) && (this.Bindings != null))
                {
                    itemNameBinding = this.Bindings.ItemNameBinding;
                }
                if ((itemNameBinding != null) && (this.Data.ItemNames == null))
                {
                    list = new List<object>();
                }
                int count = this.Data.Children.Count;
                Dictionary<IDataSeriesInfo, Binding[]> dictionary = new Dictionary<IDataSeriesInfo, Binding[]>();
                int num2 = 0;
                for (int j = 0; j < count; j++)
                {
                    IDataSeriesInfo key = this.Data.Children[j];
                    Binding[] memberPaths = key.MemberPaths;
                    if ((memberPaths != null) && (this.Data.Children[j].ItemsSource == null))
                    {
                        dictionary.Add(key, memberPaths);
                        num2 += memberPaths.Length;
                    }
                }
                IEnumerator enumerator = itemsSource.GetEnumerator();
                DataUtils.TryReset(enumerator);
                List<object>[] listArray = new List<object>[num2];
                int index = 0;
                index = 0;
                while (index < listArray.Length)
                {
                    listArray[index] = new List<object>();
                    index++;
                }
                DataBindingProxy proxy = new DataBindingProxy();
                while (enumerator.MoveNext())
                {
                    object current = enumerator.Current;
                    index = 0;
                    proxy.DataContext = current;
                    if (list != null)
                    {
                        list.Add(proxy.GetValue(itemNameBinding));
                    }
                    foreach (KeyValuePair<IDataSeriesInfo, Binding[]> pair in dictionary)
                    {
                        Binding[] bindingArray2 = pair.Value;
                        for (int k = 0; k < bindingArray2.Length; k++)
                        {
                            if (bindingArray2[k] != null)
                            {
                                listArray[index++].Add(proxy.GetValue(bindingArray2[k]));
                            }
                        }
                    }
                    proxy.DataContext = null;
                    if (current is INotifyPropertyChanged)
                    {
                        this.AddINP((INotifyPropertyChanged)current);
                    }
                }
                index = 0;
                foreach (KeyValuePair<IDataSeriesInfo, Binding[]> pair2 in dictionary)
                {
                    Binding[] bindingArray3 = pair2.Value;
                    for (int m = 0; m < bindingArray3.Length; m++)
                    {
                        if (bindingArray3[m] != null)
                        {
                            pair2.Key.SetResolvedValues(m, listArray[index++].ToArray());
                        }
                    }
                }
                if ((list != null) && (list.Count > 0))
                {
                    this.Data.ItemNamesInternal = list.ToArray();
                }
            }
            this.Data.Aggregate = this.Aggregate;
            for (int i = 0; i < this.Data.Children.Count; i++)
            {
                DataSeries seriesInfo = this.Data.Children[i];
                if (seriesInfo.ItemsSource != null)
                {
                    seriesInfo.PerformBinding(new Action<INotifyPropertyChanged>(this.AddINP));
                }
                renderer.AddSeries(seriesInfo);
            }
        }

        private void RemoveChildren(IList items)
        {
            if (items != null)
            {
                Panel templateChild = base.GetTemplateChild("grid") as Panel;
                if (templateChild != null)
                {
                    foreach (UIElement element in items)
                    {
                        if (templateChild.Children.Contains(element))
                        {
                            templateChild.Children.Remove(element);
                        }
                    }
                }
            }
        }

        internal void RemoveLogicalChild(object child)
        {
        }

        public void Reset(bool clearData)
        {
            this.BeginUpdate();
            this._autoSeries = false;
            this.Actions.Clear();
            this.ActionUpdateDelay = 40.0;
            if ((this.Data != null) && clearData)
            {
                this.Data.Reset();
                this.Bindings = null;
                this.StyleGenerator.Reset();
            }
            if (this.View != null)
            {
                this.View.ResetInternal();
            }
            BarColumnOptions.Reset(this);
            PieOptions.Reset(this);
            LineAreaOptions.Reset(this);
            PolarRadarOptions.Reset(this);
            this.EndUpdate();
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public void ResetData()
        {
            this.Data = null;
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeData()
        {
            return (this.Data != null);
        }

        void IDisposable.Dispose()
        {
            this.ClearAllINP();
        }

        internal bool TryCaptureMouse()
        {
            return base.CaptureMouse();
        }

        private void UpdateChildren()
        {
            Panel templateChild = base.GetTemplateChild("grid") as Panel;
            if (templateChild != null)
            {
                foreach (UIElement element in this.Children)
                {
                    ChartLegend legend = element as ChartLegend;
                    FrameworkElement element2 = element as FrameworkElement;
                    if (element2 != null)
                    {
                        if (legend != null)
                        {
                            legend.Chart = this;
                        }
                        else
                        {
                            Grid.SetColumn(element2, 1);
                            Grid.SetRow(element2, 1);
                        }
                        try
                        {
                            if (!templateChild.Children.Contains(element))
                            {
                                if (element2.Parent == null)
                                {
                                    templateChild.Children.Add(element);
                                }
                                else
                                {
                                    Panel parent = element2.Parent as Panel;
                                    if (parent != null)
                                    {
                                        parent.Children.Remove(element2);
                                        templateChild.Children.Add(element2);
                                    }
                                }
                            }
                        }
                        catch
                        {
                        }
                    }
                }
                this._dirtyChildren = false;
            }
        }

        // Properties
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ActionCollection Actions
        {
            get
            {
                if (this._actions == null)
                {
                    this._actions = new ActionCollection(this);
                    this._actions.CollectionChanged += new NotifyCollectionChangedEventHandler(this._actions_CollectionChanged);
                }
                return this._actions;
            }
        }

        [DefaultValue(40)]
        public double ActionUpdateDelay
        {
            get
            {
                return this.Actions.UpdateDelay;
            }
            set
            {
                this.Actions.UpdateDelay = value;
            }
        }

        public Aggregate Aggregate
        {
            get
            {
                return (Aggregate)base.GetValue(AggregateProperty);
            }
            set
            {
                base.SetValue(AggregateProperty, value);
            }
        }

        [TypeConverter(typeof(NullableBoolConverter))]
        public bool? AutoGenerateSeries
        {
            get
            {
                return this._autoSeries;
            }
            set
            {
                if (this._autoSeries != value)
                {
                    this._autoSeries = value;
                    this.dataChanged = true;
                    this.InvalidateChart();
                }
            }
        }

        public ChartBindings Bindings
        {
            get
            {
                return this._bindings;
            }
            set
            {
                if (this._bindings != value)
                {
                    this._bindings = value;
                    this.dataChanged = true;
                    this.InvalidateChart();
                }
            }
        }

        [Category("Appearance")]
        public ChartType ChartType
        {
            get
            {
                return (ChartType)base.GetValue(ChartTypeProperty);
            }
            set
            {
                base.SetValue(ChartTypeProperty, value);
            }
        }

        public System.Collections.ObjectModel.ObservableCollection<UIElement> Children
        {
            get
            {
                if (this._children == null)
                {
                    ChartObservableCollection observables = new ChartObservableCollection();
                    observables.OnClear += new EventHandler(this._children_Clear);
                    this._children = observables;
                    this._children.CollectionChanged += new NotifyCollectionChangedEventHandler(this._children_CollectionChanged);
                }
                return this._children;
            }
        }

        public bool ClipToBounds
        {
            get
            {
                return (bool)base.GetValue(ClipToBoundsProperty);
            }
            set
            {
                base.SetValue(ClipToBoundsProperty, value);
            }
        }

        public CornerRadius CornerRadius
        {
            get
            {
                return (CornerRadius)base.GetValue(CornerRadiusProperty);
            }
            set
            {
                base.SetValue(CornerRadiusProperty, value);
            }
        }

        public IEnumerable CustomPalette
        {
            get
            {
                return (IEnumerable)base.GetValue(CustomPaletteProperty);
            }
            set
            {
                base.SetValue(CustomPaletteProperty, value);
            }
        }

        public ResourceDictionary CustomTheme
        {
            get
            {
                return (ResourceDictionary)base.GetValue(CustomThemeProperty);
            }
            set
            {
                base.SetValue(CustomThemeProperty, value);
            }
        }

        [DefaultValue((string)null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ChartData Data
        {
            get
            {
                return (ChartData)base.GetValue(DataProperty);
            }
            set
            {
                base.SetValue(DataProperty, value);
            }
        }

        public GradientMethod GradientMethod
        {
            get
            {
                return this._gradientMethod;
            }
            set
            {
                if (this._gradientMethod != value)
                {
                    this._gradientMethod = value;
                    this.InvalidateChart();
                }
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public LegendItemCollection LegendItems
        {
            get
            {
                return (LegendItemCollection)base.GetValue(LegendItemsProperty);
            }
            private set
            {
                base.SetValue(LegendItemsProperty, value);
            }
        }

        internal LegendItems LegendItemsInternal
        {
            get
            {
                return this._litems;
            }
        }

        [DefaultValue(0), Category("Appearance")]
        public Palette Palette
        {
            get
            {
                return this.StyleGenerator.Palette;
            }
            set
            {
                this.StyleGenerator.Palette = value;
                this.forceRebuild = true;
                this.InvalidateChart();
            }
        }

        internal Renderers Renderers
        {
            get
            {
                if (this._renderers == null)
                {
                    this._renderers = new Renderers();
                }
                return this._renderers;
            }
        }

        private StyleGenerator StyleGenerator
        {
            get
            {
                if (this._stgen == null)
                {
                    this._stgen = new StyleGenerator();
                    this._stgen.CustomBrushConverter = new Converter<Brush, Brush>(this.BrushConverter);
                }
                return this._stgen;
            }
        }

        [Category("Appearance")]
        public ChartTheme Theme
        {
            get
            {
                return (ChartTheme)base.GetValue(ThemeProperty);
            }
            set
            {
                base.SetValue(ThemeProperty, value);
            }
        }

        internal int UpdateCount
        {
            get
            {
                return this._updateCount;
            }
            set
            {
                if (value <= 0)
                {
                    this._updateCount = 0;
                    this.InvalidateChart();
                }
                else
                {
                    this._updateCount = value;
                }
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ChartView View
        {
            get
            {
                return (ChartView)base.GetValue(ViewProperty);
            }
            set
            {
                base.SetValue(ViewProperty, value);
            }
        }

        internal FrameworkElement ViewElement
        {
            get
            {
                return this._viewElement;
            }
            set
            {
                try
                {
                    if (this._viewElement != value)
                    {
                        this._viewElement = value;
                        base.Content = this._viewElement;
                    }
                }
                catch (Exception)
                {
                }
            }
        }

        public VisualEffect VisualEffect
        {
            get
            {
                return this._eff;
            }
            set
            {
                if (this._eff != value)
                {
                    if (this._eff != null)
                    {
                        this._eff.EffectChanged -= new EventHandler(this.EffectChanged);
                    }
                    this._eff = value;
                    if (this._eff != null)
                    {
                        this._eff.EffectChanged += new EventHandler(this.EffectChanged);
                    }
                    this.InvalidateChart();
                }
            }
        }
    }
}
